﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Apollo;

namespace AlgoMF
{
    public class AlgoMFStrategyFactory : IApolloStrategyFactory
    {
        public ApolloStrategy createNew(string id)
        {
            return new AlgoMFStrategy(id);
        }
    }

    public class AlgoMFStrategy : ApolloStrategy, IApolloStrategyFuncListener
    {
        private Dictionary<string, ApolloMdField> lastMdDict;  //上一个时刻的市场行情
        private AlgoMFContract mainContract; //基准合约
        private Dictionary<string, AlgoMFContract> contractDict;  //该策略的所有合约

        private Dictionary<string, long> tradeVolBid; //当前的买头寸
        private Dictionary<string, long> tradeVolAsk; //当前的卖头寸
        private Dictionary<string, List<AlgoMFOrder>> bidOrderList; //报价合约的买订单
        private Dictionary<string, List<AlgoMFOrder>> askOrderList; //报价合约的卖订单
        private Dictionary<string, bool> isFirstStartBid; //第一次报买单
        private Dictionary<string, bool> isFirstStartAsk; //第一次报卖单

        private Dictionary<long, long> filledAmountDict; //报单成交手数
        private Dictionary<long, long> sumHedgeVol; //报价合约累计对冲手数

        private object lockerFirstBidFlag = new object(); //isFirstStartBid的锁
        private object lockerFirstAskFlag = new object(); //isFirstStartAsk的锁
        private object lockerBidOrder = new object();  //bidOrderList的锁
        private object lockerAskOrder = new object();  //askOrderList的锁
        private object lockerBidVol = new object();    //tradeVolBid的锁
        private object lockerAskVol = new object();    //tradeVolAsk的锁
        private object lockerFilledAmountDict = new object(); //filledAmountDict的锁
        private object lockerSumHedgeVol = new object();  //sumHedgeVol的锁

        public AlgoMFStrategy(string id)
            : base(id)
        {
            init();
        }


        private void init()
        {
            lastMdDict = new Dictionary<string, ApolloMdField>();
            mainContract = null;
            contractDict = new Dictionary<string, AlgoMFContract>();
            tradeVolBid = new Dictionary<string, long>();
            tradeVolAsk = new Dictionary<string, long>();
            bidOrderList = new Dictionary<string, List<AlgoMFOrder>>();
            askOrderList = new Dictionary<string, List<AlgoMFOrder>>();
            isFirstStartBid = new Dictionary<string, bool>();
            isFirstStartAsk = new Dictionary<string, bool>();
            filledAmountDict = new Dictionary<long, long>();
            sumHedgeVol = new Dictionary<long, long>();

        }

        public override List<Tuple<IApolloTrader, string>> getInstrumentList()
        {
            List<Tuple<IApolloTrader, string>> instrList = new List<Tuple<IApolloTrader, string>>();
            ApolloStrategy[] contractList = this.getChildStrategies();
            foreach (ApolloStrategy c in contractList)
            {
                AlgoMFContract sc = (AlgoMFContract)c;
                instrList.Add(new Tuple<IApolloTrader, string>(sc.getTrader(), sc.getInstrId()));
            }
            return instrList;
        }

        protected override bool startHandler()
        {
            ApolloGlobal.getCore().getStrategyFuncServer().registerFuncListener(this);
            ApolloStrategy[] contractList = this.getChildStrategies();
            int m = 0;
            int n = 0;
            contractDict.Clear();
            foreach (ApolloStrategy c in contractList)
            {
                AlgoMFContract contract = (AlgoMFContract)c;
                if (!contract.checkAccount())
                {
                    return false;
                }
                if (contract.getRatio() < 0)
                {
                    if (!contract.isActive())
                    {
                        ApolloGlobal.getCore().debugPrint("******警告: AlgoMF策略启动失败, 基准合约未启动******");
                        return false;
                    }
                    else
                    {
                        m++;
                        mainContract = contract;
                    }
                }
                else
                {
                    isFirstStartBid[contract.getInstrId()] = true;
                    isFirstStartAsk[contract.getInstrId()] = true;
                    if (!contract.checkContract())
                    {
                        return false;
                    }
                    if (contract.isActive())
                    {
                        n++;
                    }
                    bidOrderList[contract.getInstrId()] = new List<AlgoMFOrder>();
                    askOrderList[contract.getInstrId()] = new List<AlgoMFOrder>();
                    tradeVolBid[contract.getInstrId()] = 0;
                    tradeVolAsk[contract.getInstrId()] = 0;
                }
                contractDict.Add(contract.getInstrId(), contract);
            }
            if (n == 0)
            {
                ApolloGlobal.getCore().debugPrint("******警告: AlgoMF参数设置错误, 报价合约至少要有一个状态为on******");
                return false;
            }
            if (m != 1)
            {
                ApolloGlobal.getCore().debugPrint("******警告: AlgoMF参数设置错误, ratio只能有一个为负数******");
                return false;
            }
            foreach (ApolloStrategy c in contractList)
            {
                AlgoMFContract sc = (AlgoMFContract)c;
                sc.startListenMD();
            }
            ApolloGlobal.getCore().debugPrint("------AlgoMF策略成功启动------");
            return true;
        }

        protected override bool stopHandler()
        {
            ApolloGlobal.getCore().getStrategyFuncServer().removeFuncListener(this);
            ApolloStrategy[] contractList = this.getChildStrategies();
            foreach (ApolloStrategy c in contractList)
            {
                AlgoMFContract sc = (AlgoMFContract)c;
                sc.stopListenMD();
            }
            ApolloGlobal.getCore().getComplexOrderDb().rejectOrders(this.id);
            foreach (var bList in bidOrderList.Values)
            {
                bList.Clear();
            }
            foreach (var aList in askOrderList.Values)
            {
                aList.Clear();
            }
            bidOrderList.Clear();
            askOrderList.Clear();
            tradeVolBid.Clear();
            tradeVolAsk.Clear();
            ApolloGlobal.getCore().debugPrint("------AlgoMF策略成功关闭------");
            return true;
        }

        private ApolloStrategyInstrumentState getInstrumentState(string instrumentId)
        {
            return ApolloGlobal.getCore().getStatistics().getStrategyInstrumentState(getId(), instrumentId);
        }

        public void onMarketChanged(ApolloMdField data, int changeFlag)
        {
            string instrId = data.InstrumentID;
            AlgoMFContract contract = contractDict[instrId];
            if (contract == mainContract)
            {
                foreach (AlgoMFContract subContract in contractDict.Values)
                {
                    if (subContract != mainContract && subContract.isActive())
                    {
                        processContract(subContract, data);
                    }
                }
            }
            lastMdDict[instrId] = data;
        }

        private void processContract(AlgoMFContract subContract, ApolloMdField data)
        {
            ApolloMdField mainMd, subMd;
            if (!lastMdDict.TryGetValue(mainContract.getInstrId(), out mainMd) || !lastMdDict.TryGetValue(subContract.getInstrId(), out subMd))
            {
                return;
            }
            ApolloGlobal.getCore().debugPrint("------ AlgoMF收到行情数据: data.Bid1=[{0}] data.Ask1=[{1}] mainMd.Bid1=[{2}] mainMd.Ask1=[{3}] sub.instr=[{4}] sub.Bid1=[{5}] sub.Ask1=[{6}]", data.BidPrice1, data.AskPrice1, mainMd.BidPrice1, mainMd.AskPrice1, subContract.getInstrId(), subMd.BidPrice1, subMd.AskPrice1);

            // 第一次启动
            bool bidFlag = false;
            bool askFlag = false;
            lock (lockerFirstBidFlag)
            {
                bidFlag = isFirstStartBid[subContract.getInstrId()];
            }
            lock (lockerFirstAskFlag)
            {
                askFlag = isFirstStartAsk[subContract.getInstrId()];
            }

            if (bidFlag)
            {
                long contractBid = data.BidPrice1 - (mainContract.getSellThrd() - subContract.getBuyThrd());
                if (subContract.getLongLim() > 0)
                {
                    lock (lockerFirstBidFlag)
                    {
                        isFirstStartBid[subContract.getInstrId()] = false;
                    }
                    addOrder(subContract, contractBid, ApolloOrderDirection.Buy);
                }

            }
            else
            {
                ApolloGlobal.getCore().debugPrint("------subContract LongLim=[{0}] ShortLim=[{1}] BuyThrd=[{2}] SellThrd=[{3}] Qty=[{4}] LevelLim=[{5}] DownPriLim=[{6}] UpPriLim=[{7}] Tol_TW=[{8}] Tick=[{9}]------", subContract.getLongLim(), subContract.getShortLim(), subContract.getBuyThrd(), subContract.getSellThrd(), subContract.getQty(), subContract.getLevelLim(), subContract.getDownPriLim(), subContract.getUpPriLim(), subContract.getToleranceTW(), subContract.getProductInfo().TickValue);
                ApolloGlobal.getCore().debugPrint("------mainContract LongLim=[{0}] ShortLim=[{1}] BuyThrd=[{2}] SellThrd=[{3}] Qty=[{4}] LevelLim=[{5}] DownPriLim=[{6}] UpPriLim=[{7}] Tol_TW=[{8}] Tick=[{9}]------", mainContract.getLongLim(), mainContract.getShortLim(), mainContract.getBuyThrd(), mainContract.getSellThrd(), mainContract.getQty(), mainContract.getLevelLim(), mainContract.getDownPriLim(), mainContract.getUpPriLim(), mainContract.getToleranceTW(), mainContract.getProductInfo().TickValue);
                if (subContract.getLongLim() > 0)
                {
                    processLongLim(subContract, data, mainMd, subMd);
                }
            }

            if (askFlag)
            {
                long contractAsk = data.AskPrice1 - (mainContract.getBuyThrd() - subContract.getSellThrd());
                if (subContract.getShortLim() > 0)
                {
                    lock (lockerFirstAskFlag)
                    {
                        isFirstStartAsk[subContract.getInstrId()] = false;
                    }
                    addOrder(subContract, contractAsk, ApolloOrderDirection.Sell);
                }
            }
            else
            {
                ApolloGlobal.getCore().debugPrint("------subContract LongLim=[{0}] ShortLim=[{1}] BuyThrd=[{2}] SellThrd=[{3}] Qty=[{4}] LevelLim=[{5}] DownPriLim=[{6}] UpPriLim=[{7}] Tol_TW=[{8}] Tick=[{9}]------", subContract.getLongLim(), subContract.getShortLim(), subContract.getBuyThrd(), subContract.getSellThrd(), subContract.getQty(), subContract.getLevelLim(), subContract.getDownPriLim(), subContract.getUpPriLim(), subContract.getToleranceTW(), subContract.getProductInfo().TickValue);
                ApolloGlobal.getCore().debugPrint("------mainContract LongLim=[{0}] ShortLim=[{1}] BuyThrd=[{2}] SellThrd=[{3}] Qty=[{4}] LevelLim=[{5}] DownPriLim=[{6}] UpPriLim=[{7}] Tol_TW=[{8}] Tick=[{9}]------", mainContract.getLongLim(), mainContract.getShortLim(), mainContract.getBuyThrd(), mainContract.getSellThrd(), mainContract.getQty(), mainContract.getLevelLim(), mainContract.getDownPriLim(), mainContract.getUpPriLim(), mainContract.getToleranceTW(), mainContract.getProductInfo().TickValue);
                if (subContract.getShortLim() > 0)
                {
                    processShortLim(subContract, data, mainMd, subMd);
                }
            }

        }

        private void processLongLim(AlgoMFContract subContract, ApolloMdField data, ApolloMdField mainMd, ApolloMdField subMd)
        {
            if (data.BidPrice1 <= 0)
            {
                return;
            }
            lock (lockerBidOrder)
            {
                if (bidOrderList.ContainsKey(subContract.getInstrId()))
                {
                    for (int i = bidOrderList[subContract.getInstrId()].Count - 1; i >= 0; i--)
                    {
                        if (bidOrderList[subContract.getInstrId()][i].status == ApolloOrderStatus.AllTraded || bidOrderList[subContract.getInstrId()][i].status == ApolloOrderStatus.Canceled)
                        {
                            bidOrderList[subContract.getInstrId()].Remove(bidOrderList[subContract.getInstrId()][i]);
                        }
                    }
                }
            }

            long contractBid = data.BidPrice1 - (mainContract.getSellThrd() - subContract.getBuyThrd());
            List<AlgoMFOrder> todoBidList = new List<AlgoMFOrder>();
            lock (lockerBidOrder)
            {
                todoBidList = bidOrderList[subContract.getInstrId()];
            }
            long bidHigh;
            if (todoBidList.Count == 0)
            {
                bidHigh = 0;
            }
            else
            {
                bidHigh = todoBidList[0].price;
                for (int i = 1; i < todoBidList.Count; i++)
                {
                    if (todoBidList[i].price > bidHigh)
                    {
                        bidHigh = todoBidList[i].price;
                    }
                }
            }

            ApolloGlobal.getCore().debugPrint("------买方向, bidHigh=[{0}]------", bidHigh);

            // 条件3
            if (contractBid >= (bidHigh - subContract.getToleranceTW() * subContract.getProductInfo().TickValue) && contractBid <= (bidHigh + subContract.getToleranceTW() * subContract.getProductInfo().TickValue))
            {
                ApolloGlobal.getCore().debugPrint("------买方向, 满足条件3, 不操作 instr=[{0}] contractBid=[{1}] bidHigh=[{2}] Tol_TW=[{3}] Tick=[{4}]------", subContract.getInstrId(), contractBid, bidHigh, subContract.getToleranceTW(), subContract.getProductInfo().TickValue);
                return;
            }
            else if (contractBid < bidHigh - subContract.getToleranceTW() * subContract.getProductInfo().TickValue)
            {
                ApolloGlobal.getCore().debugPrint("------买方向, 满足条件2, 先撤单再下单 instr=[{0}] contractBid=[{1}] bidHigh=[{2}] Tol_TW=[{3}] Tick=[{4}]------", subContract.getInstrId(), contractBid, bidHigh, subContract.getToleranceTW(), subContract.getProductInfo().TickValue);
                List<AlgoMFOrder> subOrderList = new List<AlgoMFOrder>();
                lock (lockerBidOrder)
                {
                    subOrderList = bidOrderList[subContract.getInstrId()];
                }
                long price = contractBid + subContract.getToleranceTW() * subContract.getProductInfo().TickValue;
                List<AlgoMFOrder> cancelList = subOrderList.Where(i => i.price > price).ToList();
                ApolloGlobal.getCore().debugPrint("------买方向, 要撤单的数量=[{0}] instr=[{1}]------", cancelList.Count, subContract.getInstrId());
                if (cancelList.Count > 0)
                {
                    for (int i = cancelList.Count - 1; i >= 0; i--)
                    {
                        AlgoMFOrder canOrder = cancelList[i];
                        ApolloOrderCancelRspCallback.monitor(canOrder,
                            (ApolloExchangeEventContext ect) =>
                            {
                                if (canOrder.status == ApolloOrderStatus.Canceled)
                                {
                                    ApolloGlobal.getCore().debugPrint("------买方向, 满足条件2时成功撤单 instr=[{0}] price=[{1}] quantity=[{2}] filledAmount=[{3}] orderRef=[{4}]------", subContract.getInstrId(), canOrder.price, canOrder.quantity, canOrder.filledAmount, canOrder.orderRef);
                                    return;
                                }
                            }, null);
                        ApolloGlobal.getCore().debugPrint("------买方向, 撤单instr=[{0}] orderRef=[{1}] price=[{2}]------", canOrder.instrumentId, canOrder.orderRef, canOrder.price);
                        canOrder.reject();
                        lock (lockerBidOrder)
                        {
                            bidOrderList[subContract.getInstrId()].Remove(canOrder);
                        }
                    }
                }
                //撤单后继续下一步，下单
            }
            else
            {
                ApolloGlobal.getCore().debugPrint("------买方向, 满足条件1, instr=[{0}] contractBid=[{1}] bidHigh=[{2}] Tol_TW=[{3}] Tick=[{4}]------", subContract.getInstrId(), contractBid, bidHigh, subContract.getToleranceTW(), subContract.getProductInfo().TickValue);
            }
            List<AlgoMFOrder> subList = new List<AlgoMFOrder>();
            lock (lockerBidOrder)
            {
                subList = bidOrderList[subContract.getInstrId()];
            }
            List<AlgoMFOrder> list = subList.Where(i => i.price == contractBid).ToList();
            if (list.Count > 0)
            {
                ApolloGlobal.getCore().debugPrint("******警告: 买方向, 拟提交的买单在对应价格已有报单 instr=[{0}] contractBid=[{1}]******", subContract.getInstrId(), contractBid);
                return;
            }
            // 判断档位
            if (subList.Count < subContract.getLevelLim())
            {
                ApolloGlobal.getCore().debugPrint("------买方向, 报单后档位不超过LevelLim, 直接报单 instr=[{0}] count=[{1}] LevelLim=[{2}]------", subContract.getInstrId(), subList.Count, subContract.getLevelLim());
                addOrder(subContract, contractBid, ApolloOrderDirection.Buy);
            }
            else
            {
                AlgoMFOrder order = subList[0];
                long distance = Math.Abs(order.price - subMd.BidPrice1);
                for (int i = 1; i < subList.Count; i++)
                {
                    AlgoMFOrder bidOrder = subList[i];
                    long dis = Math.Abs(bidOrder.price - subMd.BidPrice1);
                    if (dis >= distance)
                    {
                        distance = dis;
                        order = bidOrder;
                    }
                }
                if (Math.Abs(contractBid - subMd.BidPrice1) > distance)
                {
                    ApolloGlobal.getCore().debugPrint("******买方向, 拟报价比当前档位中的价格距离市场价更远, 不操作, contractBid=[{0}] subMd.BidPrice1=[{1}] worstPrice=[{2}]******", contractBid, subMd.BidPrice1, order.price);
                    return;
                }
                ApolloGlobal.getCore().debugPrint("------买方向, 报单后档位超过LevelLim, 撤最差档位 instr=[{0}] LevelLim=[{1}] cancelOrderPrice=[{2}] contractBid=[{3}]------", subContract.getInstrId(), subContract.getLevelLim(), order.price, contractBid);
                ApolloOrderCancelRspCallback.monitor(order,
                    (ApolloExchangeEventContext cxt) =>
                    {
                        if (order.status == ApolloOrderStatus.Canceled)
                        {
                            ApolloGlobal.getCore().debugPrint("------买方向, 报单超过LevelLim后成功撤单最差档位 instr=[{0}] worstPrice=[{1}] contractBid=[{2}] orderRef=[{3}]------", subContract.getInstrId(), order.price, contractBid, order.orderRef);
                            return;
                        }
                    }, null);
                order.reject();
                lock (lockerBidOrder)
                {
                    bidOrderList[subContract.getInstrId()].Remove(order);
                }
                addOrder(subContract, contractBid, ApolloOrderDirection.Buy);
            }



        }

        private void processShortLim(AlgoMFContract subContract, ApolloMdField data, ApolloMdField mainMd, ApolloMdField subMd)
        {
            if (data.AskPrice1 < 0)
            {
                return;
            }

            lock (lockerAskOrder)
            {
                if (askOrderList.ContainsKey(subContract.getInstrId()))
                {
                    for (int i = askOrderList[subContract.getInstrId()].Count - 1; i >= 0; i--)
                    {
                        if (askOrderList[subContract.getInstrId()][i].status == ApolloOrderStatus.AllTraded || askOrderList[subContract.getInstrId()][i].status == ApolloOrderStatus.Canceled)
                        {
                            askOrderList[subContract.getInstrId()].Remove(askOrderList[subContract.getInstrId()][i]);
                        }
                    }
                }
            }

            long contractAsk = data.AskPrice1 - (mainContract.getBuyThrd() - subContract.getSellThrd());
            List<AlgoMFOrder> todoAskList = new List<AlgoMFOrder>();
            lock (lockerAskOrder)
            {
                todoAskList = askOrderList[subContract.getInstrId()];
            }
            long askLow;
            if (todoAskList.Count == 0)
            {
                askLow = long.MaxValue;
            }
            else
            {
                askLow = todoAskList[0].price;
                for (int i = 1; i < todoAskList.Count; i++)
                {
                    if (todoAskList[i].price < askLow)
                    {
                        askLow = todoAskList[i].price;
                    }
                }
            }
            ApolloGlobal.getCore().debugPrint("------卖方向, askLow=[{0}]------", askLow);

            // 条件3
            if (contractAsk >= (askLow - subContract.getToleranceTW() * subContract.getProductInfo().TickValue) && (contractAsk <= askLow + subContract.getToleranceTW() * subContract.getProductInfo().TickValue))
            {
                ApolloGlobal.getCore().debugPrint("------卖方向, 满足条件3, 不操作 instr=[{0}] contractAsk=[{1}] askLow=[{2}] Tol_TW=[{3}] Tick=[{4}]------", subContract.getInstrId(), contractAsk, askLow, subContract.getToleranceTW(), subContract.getProductInfo().TickValue);
                return;
            }
            else if (contractAsk > (askLow + subContract.getToleranceTW() * subContract.getProductInfo().TickValue))
            {
                ApolloGlobal.getCore().debugPrint("------卖方向, 满足条件2, 先撤单再下单 instr=[{0}] contractAsk=[{1}] askLow=[{2}] Tol_TW=[{3}] Tick=[{4}]------", subContract.getInstrId(), contractAsk, askLow, subContract.getToleranceTW(), subContract.getProductInfo().TickValue);
                List<AlgoMFOrder> subOrderList = new List<AlgoMFOrder>();
                lock (lockerAskOrder)
                {
                    subOrderList = askOrderList[subContract.getInstrId()];
                }
                long price = contractAsk - subContract.getToleranceTW() * subContract.getProductInfo().TickValue;
                List<AlgoMFOrder> cancelList = subOrderList.Where(i => i.price < price).ToList();
                ApolloGlobal.getCore().debugPrint("------卖方向, 要撤单的数量=[{0}] instr=[{1}]------", cancelList.Count, subContract.getInstrId());
                if (cancelList.Count > 0)
                {
                    for (int i = cancelList.Count - 1; i >= 0; i--)
                    {
                        AlgoMFOrder canOrder = cancelList[i];
                        ApolloOrderCancelRspCallback.monitor(canOrder,
                            (ApolloExchangeEventContext ect) =>
                            {
                                if (canOrder.status == ApolloOrderStatus.Canceled)
                                {
                                    ApolloGlobal.getCore().debugPrint("------卖方向, 满足条件2时成功撤单 instr=[{0}] price=[{1}] quantity=[{2}] filledAmount=[{3}] orderRef=[{4}]------", subContract.getInstrId(), canOrder.price, canOrder.quantity, canOrder.filledAmount, canOrder.orderRef);
                                    return;
                                }
                            }, null);
                        ApolloGlobal.getCore().debugPrint("------卖方向, 撤单instr=[{0}] price=[{2}]------", canOrder.instrumentId, canOrder.price);
                        canOrder.reject();
                        lock (lockerAskOrder)
                        {
                            askOrderList[subContract.getInstrId()].Remove(canOrder);
                        }
                    }
                }
                //撤单后继续下一步，下单
            }
            else
            {
                ApolloGlobal.getCore().debugPrint("------卖方向, 满足条件1, instr=[{0}] contractAsk=[{1}] askLow=[{2}] Tol_TW=[{3}] Tick=[{4}]------", subContract.getInstrId(), contractAsk, askLow, subContract.getToleranceTW(), subContract.getProductInfo().TickValue);
            }
            List<AlgoMFOrder> subList = new List<AlgoMFOrder>();
            lock (lockerAskOrder)
            {
                subList = askOrderList[subContract.getInstrId()];
            }
            List<AlgoMFOrder> list = subList.Where(i => i.price == contractAsk).ToList();
            if (list.Count > 0)
            {
                ApolloGlobal.getCore().debugPrint("******警告: 卖方向, 拟提交的卖单在对应价格已有报单 instr=[{0}] contractAsk=[{1}]******", subContract.getInstrId(), contractAsk);
                return;
            }
            // 判断档位
            if (subList.Count < subContract.getLevelLim())
            {
                ApolloGlobal.getCore().debugPrint("------卖方向, 报单后档位不超过LevelLim, 直接报单 instr=[{0}] count=[{1}] LevelLim=[{2}]------", subContract.getInstrId(), subList.Count, subContract.getLevelLim());
                addOrder(subContract, contractAsk, ApolloOrderDirection.Sell);
            }
            else
            {
                AlgoMFOrder order = subList[0];
                long distance = Math.Abs(order.price - subMd.AskPrice1);
                for (int i = 1; i < subList.Count; i++)
                {
                    AlgoMFOrder askOrder = subList[i];
                    long dis = Math.Abs(askOrder.price - subMd.AskPrice1);
                    if (dis >= distance)
                    {
                        distance = dis;
                        order = askOrder;
                    }
                }
                if (Math.Abs(contractAsk - subMd.AskPrice1) > distance)
                {
                    ApolloGlobal.getCore().debugPrint("******卖方向, 拟报价比当前档位中的价格距离市场价更远, 不操作, contractAsk=[{0}] subMd.AskPrice1=[{1}] worstPrice=[{2}]******", contractAsk, subMd.AskPrice1, order.price);
                    return;
                }
                ApolloGlobal.getCore().debugPrint("------卖方向, 报单后档位超过LevelLim, 撤最差档位 instr=[{0}] LevelLim=[{1}] cancelOrderPrice=[{2}] contractAsk=[{3}]------", subContract.getInstrId(), subContract.getLevelLim(), order.price, contractAsk);
                ApolloOrderCancelRspCallback.monitor(order,
                    (ApolloExchangeEventContext cxt) =>
                    {
                        if (order.status == ApolloOrderStatus.Canceled)
                        {
                            ApolloGlobal.getCore().debugPrint("------卖方向, 报单超过LevelLim后成功撤单最差档位 instr=[{0}] worstPrice=[{1}] contractAsk=[{2}] orderRef=[{3}]------", subContract.getInstrId(), order.price, contractAsk, order.orderRef);
                            return;
                        }
                    }, null);
                order.reject();
                lock (lockerAskOrder)
                {
                    askOrderList[subContract.getInstrId()].Remove(order);
                }
                addOrder(subContract, contractAsk, ApolloOrderDirection.Sell);
            }
        }

        public long hedgeQty(string subContractInstr, int subRatio, long quantity, long curFilledAmount, long orderRef, ApolloOrderDirection dir, long price)
        {
            if (dir == ApolloOrderDirection.Buy)
            {
                lock (lockerBidVol)
                {
                    tradeVolBid[subContractInstr] += curFilledAmount;
                }
            }
            else
            {
                lock (lockerAskVol)
                {
                    tradeVolAsk[subContractInstr] += curFilledAmount;
                }
            }
            lock (lockerFilledAmountDict)
            {
                if (!filledAmountDict.ContainsKey(orderRef))
                {
                    filledAmountDict[orderRef] = curFilledAmount;
                }
                else
                {
                    filledAmountDict[orderRef] += curFilledAmount;
                }
            }
            long hVol = 0;
            if (quantity == filledAmountDict[orderRef])
            {
                lock (lockerSumHedgeVol)
                {
                    long tmp;
                    if (sumHedgeVol.TryGetValue(orderRef, out tmp))
                    {
                        long theoryVol = Convert.ToInt32(Math.Abs(Math.Round((decimal)(filledAmountDict[orderRef] * mainContract.getRatio() / subRatio))));
                        hVol = theoryVol - tmp;
                        sumHedgeVol.Remove(orderRef);
                    }
                    else
                    {
                        hVol = Convert.ToInt32(Math.Abs(Math.Round((decimal)(filledAmountDict[orderRef] * mainContract.getRatio() / subRatio))));
                    }
                }
                lock (lockerFilledAmountDict)
                {
                    filledAmountDict.Remove(orderRef);
                }
                lock (lockerBidOrder)
                {
                    List<AlgoMFOrder> bidList = bidOrderList[subContractInstr];
                    for (int i = bidList.Count - 1; i >= 0; i--)
                    {
                        if (bidList[i].price == price)
                        {
                            ApolloGlobal.getCore().debugPrint("------全部成交, 移除成交买单 instr=[{0}] price[{1}]------", bidList[i].instrumentId, bidList[i].price);
                            bidOrderList[subContractInstr].Remove(bidList[i]);
                        }
                    }
                }
                lock (lockerAskOrder)
                {
                    List<AlgoMFOrder> askList = askOrderList[subContractInstr];
                    for (int i = askList.Count - 1; i >= 0; i--)
                    {
                        if (askList[i].price == price)
                        {
                            ApolloGlobal.getCore().debugPrint("------全部成交, 移除成交卖单 instr=[{0}] price=[{1}]------", askList[i].instrumentId, askList[i].price);
                            askOrderList[subContractInstr].Remove(askList[i]);
                        }
                    }
                }
            }
            else
            {
                lock (lockerSumHedgeVol)
                {
                    long tmp;
                    if (sumHedgeVol.TryGetValue(orderRef, out tmp))
                    {
                        long theoryVol = Convert.ToInt32(Math.Abs(Math.Round((decimal)(filledAmountDict[orderRef] * mainContract.getRatio() / subRatio))));
                        hVol = theoryVol - tmp;
                        sumHedgeVol[orderRef] = theoryVol;
                    }
                    else
                    {
                        hVol = Convert.ToInt32(Math.Abs(Math.Round((decimal)(filledAmountDict[orderRef] * mainContract.getRatio() / subRatio))));
                        sumHedgeVol[orderRef] = hVol;
                    }
                }
            }
            return hVol;
        }

        private void addOrder(AlgoMFContract subContract, long price, ApolloOrderDirection dir)
        {
            if (dir == ApolloOrderDirection.Buy)
            {
                long bidV = 0;
                lock (lockerBidVol)
                {
                    bidV = tradeVolBid[subContract.getInstrId()];
                }
                if (bidV >= subContract.getLongLim())
                {
                    ApolloGlobal.getCore().debugPrint("******警告: 买方向, 挂单量达到LongLim, 不增档 instr=[{0}] tradeVolBid=[{1}] LongLim=[{2}]******", subContract.getInstrId(), bidV, subContract.getLongLim());
                    return;
                }
                if (price < subContract.getDownPriLim() || price > subContract.getUpPriLim())
                {
                    ApolloGlobal.getCore().debugPrint("******警告: 买方向, 报价不在DownPriLim与UpPriLim区间内, 不报单 instr=[{0}] price=[{1}] DownPriLim=[{2}] UpPriLim=[{3}]******", subContract.getInstrId(), price, subContract.getDownPriLim(), subContract.getUpPriLim());
                    return;
                }
                long quantity = Math.Abs(subContract.getQty() * subContract.getRatio());
                AlgoMFOrder order = new AlgoMFOrder(getId(), "AlgoMF", quantity, price, dir, subContract, mainContract, this);
                order.submit(ApolloGlobal.getCore().getComplexOrderDb());
                ApolloGlobal.getCore().debugPrint("------提交买单 instr=[{0}] quantity=[{1}] price=[{2}]------", subContract.getInstrId(), quantity, price);
                lock (lockerBidOrder)
                {
                    bidOrderList[subContract.getInstrId()].Add(order);
                }

            }
            else
            {
                long askV = 0;
                lock (lockerAskVol)
                {
                    askV = tradeVolAsk[subContract.getInstrId()];
                }
                if (askV >= subContract.getShortLim())
                {
                    ApolloGlobal.getCore().debugPrint("******警告: 卖方向, 挂单量达到ShortLim, 不增档 instr=[{0}] tradeVolAsk=[{1}] ShortLim=[{2}]******", subContract.getInstrId(), askV, subContract.getShortLim());
                    return;
                }
                if (price < subContract.getDownPriLim() || price > subContract.getUpPriLim())
                {
                    ApolloGlobal.getCore().debugPrint("******警告: 卖方向, 报价不在DownPriLim与UpPriLim区间内, 不报单 instr=[{0}] price=[{1}] DownPriLim=[{2}] UpPriLim=[{3}]******", subContract.getInstrId(), price, subContract.getDownPriLim(), subContract.getUpPriLim());
                    return;
                }
                long quantity = Math.Abs(subContract.getQty() * subContract.getRatio());
                AlgoMFOrder order = new AlgoMFOrder(getId(), "AlgoMF", quantity, price, dir, subContract, mainContract, this);
                order.submit(ApolloGlobal.getCore().getComplexOrderDb());
                ApolloGlobal.getCore().debugPrint("------提交卖单 instr=[{0}] quantity=[{1}] price=[{2}]------", subContract.getInstrId(), quantity, price);
                lock (lockerAskOrder)
                {
                    askOrderList[subContract.getInstrId()].Add(order);
                }
            }
        }

        #region IAPolloStrategyFuncListener
        public string[] getStrategyFuncNames()
        {
            return new string[] { };
        }

        public void onStrategyFuncRequest(ApolloStrategyFuncRequest request)
        {

        }

        public void onStrategyFuncResponse(ApolloStrategyFuncResponse response)
        {

        }
        #endregion

    }

}
